---@class Battle.Skill:Battle.SkillBase
---@field New fun():Battle.Skill
local Skill = Battle.CreateClass("Skill", Battle.SkillBase)
Battle.Skill = Skill
---@param actor Battle.Entity
function Skill:OnCreate(actor, skillId)
    Battle.SkillBase.OnCreate(self, actor, skillId)
    self:InitSkillConfig()
    self.targetId = 0;
    self.targetHitPos = self.targetHitPos or Vector3.New()
end
function Skill:OnDestroy()
    Battle.SkillBase.OnDestroy(self)
    if self.script then
        self.script:BaseDestroy()
    end
    self.nextSkillId = 0
    self.script = nil
end

function Skill:InitSkillConfig()
    ---@type Battle.SkillData
    self.skillData = Battle.SkillData.New(self.skillId)
    self.maxCd = self.skillData.maxCd
    self.initCd = self.skillData.initCd
    self.curCd = self.initCd;--当前技能cd
    self.during = self.skillData.during
    self.releaseRadius = self.skillData.releaseRadius--施法距离
    self.isFrontSwing = true;--是否已经触发前摇
    if self.curCd > 0 then
        self:StartCoolDown(self.curCd)
    end
    self:InitComponent()
    if self.skillData.scriptID > 0 then
        local script = require("Battle/Skill/SkillScript/Skill" .. self.skillData.scriptID)
        ---@type Battle.SkillScriptBase
        self.script = script.New()
        self.script:BaseOnCreate(self)
    end
    self.actor.eventSystem:FireEvent(Battle.Event.SkillCDChange,Battle.EventArgs.SkillCdChangeArgs:Create(self,self.curCd,math.max(self.maxCd,self.initCd)))
end
function Skill:InitComponent()
    ---@type Battle.SkillComponent
    local node
    ---@type Battle.SkillReleaseEmitter
    self.emitter = self:AddComponent(Battle.SkillReleaseEmitter)
    self:AddComponent(Battle.SkillRangeTipComponent)
    if self.skillData.f_Charge then
        self:AddComponent(Battle.SkillChargeComponent)
    end
    --有动作的就走事件帧，没动作走延时
    if string.IsEmpty(self.skillData.show.f_Animation) then
        if self.skillData.hitDelayTime >= 0 then
            node = self:AddComponent(Battle.SkillEventComponent)
            node:SetData("Hit")
            node:SetDelay(self.skillData.hitDelayTime)
        end
        if self.skillData.f_CastMagicSE then
            node = self:AddComponent(Battle.SkillEventComponent)
            node:SetData("ReleaseEff")
            node:SetDelay(self.skillData.f_CastMagicSE.delay)
        end
    else
        self.actor.eventSystem:FireEvent(Battle.Event.RegisterSkillFrameEvent,Battle.EventArgs.SkillArgs:Create(self))
    end
    --buff
    for k,v in pairs(self.skillData.f_IncidentalBuff) do
        node = self:AddComponent(Battle.SkillBufferComponent)
        node:SetData(false,v.type,v.buffId,v.layer)
    end
    for k,v in pairs(self.skillData.f_SelfBuff) do
        node = self:AddComponent(Battle.SkillBufferComponent)
        node:SetData(true,v.type,v.buffId,v.layer)
    end
end

function Skill:DoSkill()
    self:OnSkillInit()
    self:OnSkillStart()
end
function Skill:End(isInterrupt)
    self.actor.skillSystem:EndSkill(self.skillId,isInterrupt)
end

function Skill:Update(dt)
    Battle.SkillBase.Update(self, dt)
    if self.isEnd then
        return
    end
    if self.isStart then
        self.playingTime = self.playingTime + dt;
        if self.skillData.frontSwingTime <= self.playingTime and self.isFrontSwing then
            self.isFrontSwing = false;
            self:FrontSwingFinished();
        end
    end
    if self.script then
        self.script:Update(dt)
    end
end
---是否需要目标
function Skill:IsNeedTarget()
    return self.skillData.f_AppointTarget == 1
end
---获取攻击距离
function Skill:GetSkillRadius()
    return self.releaseRadius * (1 + (self.actor.attrSystem:GetAttr(50) / 10000))
end

function Skill:GetReleasePos()
    self.emitter:GetReleasePos()
end
--技能是否可释放
function Skill:CanRelease()
    return not self:IsInCD()
end
function Skill:IsInSkillRange()
    local radius = self.releaseRadius
    if self:IsNeedTarget() then
        local target = self.emitter:CalcReleaseTarget()
        if target then
            local p1 = self.actor.pos
            local p2 = target.pos
            local flag = Battle.BattleUtil.IsCircleIntersection(p1,radius,p2,target.radius)
            return flag
        else
            return false
        end
    else
        return true
    end
end

function Skill:DoDamage()
    local targetList = self.emitter:CalcDamageTargetList()

    local damage = self:CalcDamage()

    for k, v in pairs(targetList) do
        local damageData = Battle.BattleUtil.CalcRealDamage(damage, self.skillData.hurtType, self.actor, v,Battle.SourceType.Skill,self.skillId)
        self.actor:Damage(damageData)
        local res = DataTable.GetById("t_skillshow", self.skillId, "f_HitSE")
        if not string.IsEmpty(res) then
            Battle.EffectShowMgr.PlayEffect(res, v:GetHitPos(), self.actor.forward, 1)
        end
    end
end

function Skill:CalcDamage()
    local attrType = self.skillData.f_CalculationAttribute
    self.damageCount = self.damageCount + 1
    local index = math.min(self.damageCount, #self.skillData.f_FixedCorrect)
    local fixedCorrect = self.skillData.f_FixedCorrect[index] or 0
    local fixValue = self.skillData.f_FixedCalculation
    local percent = self.actor.attrSystem:GetAtk() * fixedCorrect / 10000
    local damage = fixValue + percent
    return damage,attrType
end
function Skill:Hit()
    if self.isEnd then
        return
    end
    self:DoDamage()
end
function Skill:CheckUseSkill()
    if self.actor.isDead then return false end
    if self.skillData.skillType == Battle.SkillType.Passive then
        return false;
    end
    if self:IsInCD() then
        --cd冷却中
        return false;
    end
    if self:IsStart() and not self:IsSkillEnd() then
        return false
    end
    if self.script and self.script:CheckSkill() then
        return false;
    end
    if self.skillData.skillType == Battle.SkillType.Normal and
            self.actor.effectStateSystem:HasState(Battle.FighterStateEnum.CAN_NOT_NORMAL_ATTACK) then
        return false
    end
    if self.skillData.skillType == Battle.SkillType.Active and self.actor.effectStateSystem:HasState(Battle.FighterStateEnum.CAN_NOT_USE_SKILL) then
        return false
    end
    return true
end
---是否需要手操
function Skill:IsNeedHand()
    return self.skillData.rangeScopeParam.type == Battle.SkillScopeType.HandCircle or self.skillData.rangeScopeParam.type == Battle.SkillScopeType.HandLine
end
---技能初始化
function Skill:OnSkillInit()
    Battle.SkillBase.OnSkillInit(self)
    self.damageCount = 0;
    self.playingTime = 0;

    local target = self.emitter:CalcReleaseTarget()
    if target then
        self.targetHitPos:SetV(target:GetHitPos())
    end
    if self.skillData.skillType == Battle.SkillType.Normal then
        self.speedRate = Battle.BattleUtil.CalcAttackDuring(self.actor) / self.during
    end
end
function Skill:AddInterruptState()
    if not self.skillData.interruptList[Battle.SkillInterruptType.Move] then
        self.actor.effectStateSystem:AddState(Battle.FighterStateEnum.CAN_NOT_MOVE)
    end
    if not self.skillData.interruptList[Battle.SkillInterruptType.control] then
        self.actor.effectStateSystem:AddState(Battle.FighterStateEnum.IMMUNITY_CTRL)
    end
    if not self.skillData.interruptList[Battle.SkillInterruptType.hit] then
        self.actor.effectStateSystem:AddState(Battle.FighterStateEnum.IMMUNITY_HIT_INTERRUPT)
    end
end
function Skill:RemoveInterruptState()
    if not self.skillData.interruptList[Battle.SkillInterruptType.Move] then
        self.actor.effectStateSystem:RemoveState(Battle.FighterStateEnum.CAN_NOT_MOVE)
    end
    if not self.skillData.interruptList[Battle.SkillInterruptType.control] then
        self.actor.effectStateSystem:RemoveState(Battle.FighterStateEnum.IMMUNITY_CTRL)
    end
    if not self.skillData.interruptList[Battle.SkillInterruptType.hit] then
        self.actor.effectStateSystem:RemoveState(Battle.FighterStateEnum.IMMUNITY_HIT_INTERRUPT)
    end
end
---技能起手(前揺)
function Skill:OnSkillStart()
    Battle.SkillBase.OnSkillStart(self)
    self:AddInterruptState()
    if self.components then
        for k, v in pairs(self.components) do
            v:SkillStart()
        end
    end
    if self.script then
        self.script:OnSkillStart()
    end
    self.actor.eventSystem:FireEvent(Battle.Event.SkillStart,Battle.EventArgs.SkillArgs:Create(self))
    --非分离技能
    if self.skillData.f_SeparateSkill == 0 then
        self.actor:EnterState(Battle.ActionState.attack,self.skillId)
    end
end
function Skill:EndSkill()
    self.isEnd = true
    self.isStart = false
    self.duringTime = 0
    self:OnSkillEnd()
    if self.script then
        self.script:OnSkillEnd()
    end
    self:RemoveInterruptState()
    --非分离技能
    if self.skillData.f_SeparateSkill == 0 then
        self.actor:EnterState(Battle.ActionState.idle)
    end

end
function Skill:AnimationEvent(param,checkAction)
    if checkAction then
        if not self.actor.actionStateSystem:InState(Battle.ActionState.attack) then return end
        if self.actor.actionStateSystem.curActionState.data ~= self.skillId then
            return
        end
    end
    if param == "Hit" then
        if self.skillData.releaseType == Battle.ReleaseType.Remote then
            self:FireBullet()
        elseif self.skillData.f_Charge then--冲锋
            ---@type Battle.SkillChargeComponent
            local com = self:GetComponent(Battle.SkillChargeComponent:GetType())
            com:Execute()
        else
            self:Hit()
        end
    elseif param == "ReleaseEff" then
        self:FireReleaseEffect()
    end
end
function Skill:FireBullet()
    local showCfg = self.skillData.show
    local bulletId = self.skillData.f_BulletID
    local param = decodeJsonStrToTable(showCfg.f_BulletDeviation) or {}
    local offset = Vector3.New(param[1],param[2],param[3])
    local target = self.emitter:GetReleaseTarget()
    local targetId = target and target:GetId() or 0
    local p = self.emitter:GetReleasePos()
    local f = self.emitter:GetReleaseForward()
    local right = Vector3.Cross(Vector3.New(0,1,0),f)
    right:SetNormalize()
    local pos = f * offset.z + right*offset.x
    pos.y = pos.y + offset.y

    pos:Set(p.x+pos.x,p.y+pos.y,p.z+pos.z)
    Battle.BulletSystem.CreateBullet(bulletId,self,targetId,pos,f)
end
function Skill:FireReleaseEffect()
    --施法特效
    local param = self.skillData.f_CastMagicSE
    local p = self.emitter:GetReleasePos()
    local f = self.emitter:GetReleaseForward()
    local right = Vector3.Cross(Vector3.New(0,1,0),f)
    right:SetNormalize()
    Battle.EffectShowMgr.PlayEffect(param.res,p,right,self.during-param.delay)
end